/*
 * Copyright (C) 2008 GeoScheduler Team, as stated on <http://www.geoscheduler.org/authors>.
 * 
 * This file is part of GeoScheduler.
 * 
 * GeoScheduler is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GeoScheduler is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with GeoScheduler. If not, see <http://www.gnu.org/licenses/>.
 */
package org.geoscheduler.jersey;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.sun.ws.rest.api.core.ResourceConfig;
import com.sun.ws.rest.spi.container.WebApplication;
import com.sun.ws.rest.spi.container.servlet.ServletContainer;
import com.sun.ws.rest.spi.service.ComponentProvider;

/**
 * <h2>SpringServlet</h2>
 * <p>
 * Spring support of Jeresey resources.
 * </p>
 * <p>
 * <a
 * href="http://blogs.sun.com/sandoz/entry/integrating_jersey_and_spring_take">http://blogs.sun.com/sandoz/entry/integrating_jersey_and_spring_take</a>
 * </p>
 * 
 * @author lko
 */
public class SpringServlet extends ServletContainer {

	private static final long serialVersionUID = -8037271105363939853L;

	private static class SpringComponentProvider implements ComponentProvider {
		private ApplicationContext springContext;

		SpringComponentProvider(ApplicationContext springContext) {
			this.springContext = springContext;
		}

		@SuppressWarnings("unchecked")
		private String getBeanName(Class c) {
			String names[] = springContext.getBeanNamesForType(c);
			if (names.length == 0) {
				return null;
			} else if (names.length > 1) {
				throw new RuntimeException("Multiple configured beans for " + c.getName());
			}
			return names[0];
		}

		@SuppressWarnings("unchecked")
		public Object getInstance(Scope scope, Class c) throws InstantiationException, IllegalAccessException {
			String beanName = getBeanName(c);
			if (beanName == null)
				return null;

			if (scope == Scope.WebApplication && springContext.isSingleton(beanName)) {
				return springContext.getBean(beanName, c);
			} else if (scope == Scope.ApplicationDefined && springContext.isPrototype(beanName)
					&& !springContext.isSingleton(beanName)) {
				return springContext.getBean(beanName, c);
			} else {
				return null;
			}
		}

		@SuppressWarnings("unchecked")
		public Object getInstance(Scope scope, Constructor contructor, Object[] parameters)
				throws InstantiationException, IllegalArgumentException, IllegalAccessException,
				InvocationTargetException {
			return null;
		}

		public void inject(Object instance) {
		}
	};

	@Override
	protected void initiate(ResourceConfig rc, WebApplication wa) {
		ApplicationContext springContext = WebApplicationContextUtils
				.getRequiredWebApplicationContext(getServletContext());

		wa.initiate(rc, new SpringComponentProvider(springContext));
	}
}